/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.action;

import java.util.Iterator;

import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.SWTGraphics;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.editparts.LayerManager;
import org.eclipse.gef.ui.parts.GraphicalEditor;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;

// Based on code written for Smach
// Based on venkataramana newgroups.eclipse.org

class ImageSaveUtil {

    public static boolean save(GraphicalEditor editorPart) {
        String filename = getSaveFilePath(editorPart);
        if (filename == null)
            return false;

        int format = SWT.IMAGE_JPEG;
        if (filename.endsWith(".jpg"))
            format = SWT.IMAGE_JPEG;
        else if (filename.endsWith(".bmp"))
            format = SWT.IMAGE_BMP;
        // else if (filename.endsWith(".png")) Not currently supported by SWT
        // format = SWT.IMAGE_PNG;
        // else if (filename.endsWith(".gif")) Only supported with 1,4,8 bits per pixel
        // format = SWT.IMAGE_GIF; Unfortunately windows images are 32 bpp
        else
            return false;

        return save(editorPart, filename, format);
    }

    private static String getSaveFilePath(IEditorPart editor) {
        FileDialog fileDialog = new FileDialog(editor.getEditorSite().getShell(), SWT.SAVE);

        String[] filterExtensions = new String[] {
                "*.jpg", "*.bmp"
        };
        fileDialog.setFilterExtensions(filterExtensions);

        return fileDialog.open();
    }

    private static boolean save(GraphicalEditor editor, String filename, int format) {
        try {
            saveEditorContentsAsImage(editor, filename, format);
        } catch (Exception ex) {
            MessageDialog.openError(editor.getEditorSite().getShell(), "Save Error",
                    "Could not save editor contents");
            return false;
        }

        return true;
    }

    @SuppressWarnings("unchecked")
    private static void saveEditorContentsAsImage(GraphicalEditor editor, String saveFilePath,
            int format) {
        final GraphicalViewer viewer = (GraphicalViewer) editor.getAdapter(GraphicalViewer.class);

        /*
         * 1. First get the figure whose visuals we want to save as image. So we would
         * like to save the rooteditpart which actually hosts all the printable layers.
         * NOTE: ScalableRootEditPart manages layers and is registered graphicalviewer's
         * editpartregistry with the key LayerManager.ID ... well that is because
         * ScalableRootEditPart manages all layers that are hosted on a FigureCanvas. Many
         * layers exist for doing different things
         */

        LayerManager rootEditPart =
                (LayerManager) viewer.getEditPartRegistry().get(LayerManager.ID);
        IFigure rootFigure = rootEditPart.getLayer(LayerConstants.PRINTABLE_LAYERS);

        // Measure the diagram.
        // The actual visible part of the diagram is probably less than the
        // entire root figure. We only want to export the "interesting part".

        Rectangle bounds = null;
        try {
            // TODO Measure diagram without making any assumptions about the data
            // structure
            // Maybe move this section to the root edit part, so we can ask it.
            RootEditPart root = viewer.getRootEditPart();
            EditPart diagramContents = (EditPart) root.getChildren().get(0);
            for (Iterator iter = diagramContents.getChildren().iterator(); iter.hasNext();) {
                GraphicalEditPart childEP = (GraphicalEditPart) iter.next();
                if (bounds == null)
                    bounds = childEP.getFigure().getBounds().getCopy();
                else
                    bounds = bounds.union(childEP.getFigure().getBounds());
            }
        } catch (Exception e) {
            // NPE, class cast exceptions or some other broken assumption above
            bounds = null;
        }

        if (bounds == null)
            bounds = rootFigure.getBounds();
        // since there is nothing to save anyway

        /*
         * 2. Now we want to get the GC associated with the control on which all figures
         * are painted by SWTGraphics. For that first get the SWT Control associated with
         * the viewer on which the rooteditpart is set as contents
         */
        Control figureCanvas = viewer.getControl();
        GC figureCanvasGC = new GC(figureCanvas);

        /* 3. Create a new Graphics for an Image onto which we want to paint rootFigure */
        Image img = new Image(null, bounds.width, bounds.height);
        GC imageGC = new GC(img);
        imageGC.setBackground(figureCanvasGC.getBackground());
        imageGC.setForeground(figureCanvasGC.getForeground());
        imageGC.setFont(figureCanvasGC.getFont());
        imageGC.setLineStyle(figureCanvasGC.getLineStyle());
        imageGC.setLineWidth(figureCanvasGC.getLineWidth());
        // imageGC.setXORMode(figureCanvasGC.getXORMode());

        Graphics imgGraphics = new SWTGraphics(imageGC);
        imgGraphics.translate(-bounds.x, -bounds.y);

        try {
            /* 4. Draw rootFigure onto image. After that image will be ready for save */
            rootFigure.paint(imgGraphics);

            /* 5. Save image */
            ImageData[] imgData = new ImageData[1];
            imgData[0] = img.getImageData();

            ImageLoader imgLoader = new ImageLoader();
            imgLoader.data = imgData;
            imgLoader.save(saveFilePath, format);
        } finally {
            // release OS resources
            figureCanvasGC.dispose();
            imageGC.dispose();
            img.dispose();
        }
    }
}

public class SaveAsImageActionDelegate implements IWorkbenchWindowActionDelegate {

    private IWorkbenchWindow window;

    public void dispose() {
        window = null;
    }

    public void init(final IWorkbenchWindow window) {
        this.window = window;
    }

    public void run(final IAction action) {
        final IWorkbenchPage activePage = window.getActivePage();
        if (activePage == null)
            return;

        final IEditorPart activeEditor = activePage.getActiveEditor();
        if (!(activeEditor instanceof GraphicalEditor))
            return;

        final GraphicalEditor editor = (GraphicalEditor) activeEditor;
        ImageSaveUtil.save(editor);
    }

    public void selectionChanged(IAction action, ISelection selection) {
        // noop
    }
}
